import axios from "axios";
import { AxiosInstance, CreateAxiosDefaults, AxiosResponse } from "axios";
import { reqReject, reqResolve, resReject, resResolve } from "./interceptors";
import { RequestConfig, RequestResult } from "@/types/custom/request";
import { REQUEST_SUCCESS_CODE } from "./service";

const defaultOptions = {
  baseURL: import.meta.env.VITE_REQUEST_BASE_URL,
  timeout: 12000,
  headers: {
    "Content-Type": "application/json",
  },
  withCredentials: true,
};

export class Request {
  instance: AxiosInstance;

  constructor(options?: CreateAxiosDefaults<any>) {
    const instance = axios.create({
      ...defaultOptions,
      ...options,
    });
    instance.interceptors.request.use(reqResolve, reqReject);
    instance.interceptors.response.use(resResolve, resReject);

    this.instance = instance;
  }

  request = <T = any>(config: RequestConfig) => {
    const reqPromise = this.instance.request(config);
    return reqPromise as unknown as Promise<RequestResult<T>>;
  };

  get = async <T = any>(
    url: string,
    params?: Record<string, any> | null,
    config?: RequestConfig
  ) => {
    const reqPromise = this.instance.get(url, { ...config, params });
    return resolveResult<T>(reqPromise);
  };

  post = async <T = any>(
    url: string,
    data?: Record<string, any> | null,
    config?: RequestConfig
  ) => {
    const reqPromise = this.instance.post(url, data, config);
    return resolveResult<T>(reqPromise);
  };

  put = async <T = any>(
    url: string,
    data?: Record<string, any> | null,
    config?: RequestConfig
  ) => {
    const reqPromise = this.instance.put(url, data, config);
    return resolveResult<T>(reqPromise);
  };

  delete = async <T = any>(
    url: string,
    params?: Record<string, any> | null,
    config?: RequestConfig
  ) => {
    const reqPromise = this.instance.delete(url, { ...config, params });
    return resolveResult<T>(reqPromise);
  };
}

const resolveResult = async <T>(request: Promise<AxiosResponse<any, any>>) => {
  const result = (await request) as unknown as RequestResult<T>;
  if (result.code === REQUEST_SUCCESS_CODE) return result;
  // 请求失败直接抛出异常
  throw new Error(result.message);
};
